﻿package de.gameduell.framework.modules {
	import de.gameduell.framework.debug.Debug;
	import de.gameduell.framework.util.HashMap;
	
	import flash.geom.Point;
	import flash.utils.*;
	
	/**
	 * read global properties and overwritten/specialized local properties of modules
	 */
	public class ModuleConfig {
		
		protected static var instance:ModuleConfig;
		
		private var contextMap:HashMap;
		
		public function ModuleConfig() {
			contextMap = new HashMap();
		}
		
		public static function getInstance():ModuleConfig {
			if (instance == null) {
				instance = new ModuleConfig();
			}
			
			return instance;
		}

		/**
		 * read from independent asset (modules.xml)
		 * @param	aXML
		 */
		public function addXML(aXML:XML):void{
			//Debug.trace("ModuleConfig.addXML() " + aXML);
			
			var nodes:XMLList = aXML.children();
			addXMLList(nodes);
		}
		
		/**
		 * extract from settings (config.xml)
		 * @param	nodes
		 */
		public function addXMLList(nodes:XMLList):void {
			//Debug.trace("ModuleConfig.addXMLList() " + nodes);
			
			// var nodes:XMLList = aXML.children();
			for(var i:* in nodes){
				var node:XML = XML(nodes[i]);
				//var type:String = parseAttributeAsString(node, "type");
				//var separator:String = parseAttributeAsString(node, "separator");
				var type:String = String(node.@type).length > 0 ? node.@type : null;
				var separator:String = String(node.@separator).length > 0 ? node.@separator : null;
				
				// read as string
				var textValue:String = "" + node.text();
				
				var value:Object = textValue;
				if (separator != null) {
					// as array?
					value = convertValueToArray(textValue, type, separator);
				}
				else {
					// as simple type?
					value = convertValueToType(textValue, type);
				}
				
				contextMap.put(node.name().toString(), value);
				// Debug.trace("ModuleConfig add key=" + node.name() + " value=" + value + " type=" + getQualifiedClassName(value));
			}
		}
		
		private function convertValueToArray(value:String, type:String, separator:String):Object {
			var parts:Array = value.split(separator);
			
			// Debug.trace("array-parts:" + parts + " count=" + parts.length + " sep='" + separator + "'");
			
			var result:Array = [];
			for each(var entry:String in parts) {
				var singleValue:Object = convertValueToType(entry, type);
				result.push(singleValue);
			}
			
			return result;
		}
		
		private function convertValueToType(value:String, type:String):Object {
			if (type == "int") {
				return int(value);
			}
			else if (type == "Number") {
				return Number(value);
			}
			else if (type == "Boolean") {
				return value.toLowerCase() == "true"; // Boolean(value);
			}
			else if (type == "Point") {
				var parts:Array = value.split(",");
				return new Point( Number(parts[0]), Number(parts[1]) );
			}			
			return value;
		}
		
		
		private function parseAttributeAsString(node:XML, attributeKey:String):String {
			var result:XMLList = node.attribute(attributeKey);
			return result.length() > 0 ? "" + result.text() : null;
		}
		
		/**
		 * 
		 * @param	prefixFilter collect keys for children, overwrite global values if local values exist
		 * @param	parentMap derive from parent map (contains runtime dependencies like view, controller etc)
		 * @return
		 */
		public function getContextMap(prefixFilter:String = null, parentMap:HashMap = null):HashMap {
			
			// take base map or parent map?
			var localMap:HashMap = (parentMap != null) ? parentMap.clone() : contextMap.clone();
			
			// add local overwrites
			if (prefixFilter != null) {
				for each(var key:String in contextMap.keys) {
					var value:Object = contextMap.getValue(key);
					
					// starts with prefix ?
					if (key.indexOf(prefixFilter) == 0) {
						
						// extract local overwrite key
						var localKey:String = key.substr(prefixFilter.length);
						localMap.put(localKey, value);
					}
				}
			}
			
			return localMap;
		}
		

	}
}